package srfile

import (
	"encoding/json"
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"wails/modules/editor/models"
	sr "wails/modules/editor/services"

	"gitee.com/zhongguo168a/gocodes/datax"
	"gitee.com/zhongguo168a/gocodes/datax/convertx"
	"gitee.com/zhongguo168a/gocodes/datax/mapx"
	"gitee.com/zhongguo168a/gocodes/datax/schemax"
	"gitee.com/zhongguo168a/gocodes/datax/schemax/configx"
	"gitee.com/zhongguo168a/gocodes/gox/osx/filex"
	"gitee.com/zhongguo168a/gocodes/gox/pathx"
	"gitee.com/zhongguo168a/gocodes/myx/errorx"
	"github.com/spf13/afero"
	"zhongguo168a.top/mycodes/gocodes/utils/maputil"
)

type FileService struct {
}

func (p *FileService) GetFileContent(指定文件 string) (string, error) {
	指定文件 = models.Module.Get编辑器路径() + "/" + 指定文件
	file, err := filex.NewFileInfo(指定文件)
	if err != nil {
		return "", errorx.Wrap(err, "获取文件信息", datax.M{"指定文件": 指定文件})
	}

	bcontent, err := os.ReadFile(file.Path())
	if err != nil {
		return "", errorx.Wrap(err, "获取文件内容", datax.M{"指定文件": 指定文件})
	}

	return string(bcontent), nil
}
func (p *FileService) NewFolder(新路径 string) (string, error) {
	新路径 = models.Module.Get编辑器路径() + "/" + 新路径
	新文件, err := filex.NewFileInfo(新路径)
	if err != nil {
		return "", errorx.Wrap(err, "filex.NewFileInfo", datax.M{"新路径": 新路径})
	}

	if 新文件.IsDir() == false {
		新文件, err = filex.NewFileInfo(filepath.Dir(新文件.Path()))
		if err != nil {
			return "", errorx.Wrap(err, "filex.NewFileInfo2", datax.M{"新路径": 新文件.Path()})
		}
	}
	新路径 = 新文件.Path()
	新路径 = 新路径 + "/新建文件夹"
	新路径, err = pathx.S生成不重复的文件路径(新路径)
	if err != nil {
		return "", err
	}
	新路径 = filepath.ToSlash(新路径)
	mkerr := os.MkdirAll(新路径, fs.ModePerm)
	if mkerr != nil {
		return "", mkerr
	}
	新路径 = strings.Replace(新路径, models.Module.Get编辑器路径()+"/", "", 1)
	return 新路径, nil
}

func (p *FileService) GetFileConfig场景(场景路径 string) (string, error) {
	if strings.Index(场景路径, "world/场景") == -1 {
		return "", errorx.New("路径错误")
	}
	files := filex.NewFilter().
		IncludeSuffix(".ycj", ".map").
		GetFileInfosByPath(models.Module.H获取文件路径("config/" + 场景路径))
	content, errs := p.GetFileConfig(files)
	if len(errs) > 0 {
		return "", errs[0]
	}
	b, _ := json.Marshal(content)
	return string(b), nil
}

// todo: 需要返回错误提示
func (p *FileService) GetFileConfigAll() (string, error) {
	content, errs := p.GetFileConfigAllMap()
	if len(errs) > 0 {
		return "", errs[0]
	}
	b, _ := json.Marshal(content)
	return string(b), nil
}

func (p *FileService) GetFileConfigAllMap() (map[string]map[string]interface{}, []error) {
	files := filex.NewFilter().
		IncludeSuffix(".ycj").
		IgnoreDir(models.Module.Get编辑器路径() + "/config/world/场景").
		GetFileInfosByPath(models.Module.Get编辑器路径() + "/config")

	return p.GetFileConfig(files)
}

func (p *FileService) GetFileConfig(files []filex.IFileInfo) (map[string]map[string]interface{}, []error) {
	var list = map[string]map[string]interface{}{}
	var errs []error
	for _, info := range files {
		if info.Path() == "." {
			continue
		}

		path := func() (x string) {
			x = info.Path()
			return x
		}()
		path = filepath.ToSlash(path)

		bcontent, err := os.ReadFile(info.Path())
		m := map[string]interface{}{}
		if err != nil {
			errs = append(errs, errorx.Wrap(err, "read file", datax.M{path: info.Path()}))
			continue
		}
		err = json.Unmarshal(bcontent, &m)
		if err != nil {
			errs = append(errs, errorx.Wrap(err, "unmarshal json", datax.M{path: info.Path()}))
			continue
		}
		configPath := strings.Replace(path, models.Module.Get编辑器路径()+"/", "", 1)
		for _, val := range m {
			config := val.(map[string]interface{})
			config["_file"] = configPath
		}

		list[configPath] = m

	}

	return list, errs
}

func (*FileService) NewFile(文件路径 string, 文件类型 int, 名称 string, 内容 string) (新路径 string, err error) {
	valid := func() (x bool) {
		switch 文件类型 {
		case 0: // 无后缀
			fallthrough
		case 1:
			fallthrough
		case 2:
			return true
		case 3:
			return true
		}
		return false
	}()
	if !valid {
		return "", errorx.New("非法的参数")
	}
	suffix := func() (x string) {
		switch 文件类型 {
		case 1:
			return ".ycj"
		case 2:
			return ".scj"
		case 3:
			return ".terrain"
		}
		return
	}()

	文件名称 := "新建配置"
	if 名称 != "" {
		文件名称 = 名称
	}
	if mkerr := os.MkdirAll(models.Module.Get编辑器路径()+"/"+文件路径, fs.ModePerm); mkerr != nil {
		return "", mkerr
	}

	新路径 = models.Module.Get编辑器路径() + "/" + 文件路径 + "/" + 文件名称 + suffix
	新路径, err = pathx.S生成不重复的文件路径(新路径)
	if err != nil {
		return
	}
	新路径 = filepath.ToSlash(新路径)

	content := func() (x string) {
		if 内容 != "" {
			return 内容
		}
		switch 文件类型 {
		case 1:
			return "{}"
		case 2:
			return "{}"
		case 3:
			return "{}"
		}
		return
	}()

	err = os.WriteFile(新路径, []byte(content), fs.ModePerm)
	if err != nil {
		return
	}

	新路径 = strings.Replace(新路径, models.Module.Get编辑器路径()+"/", "", 1)
	return
}

func (*FileService) DeleteFile(指定文件 string) (err error) {
	指定文件 = filepath.ToSlash(指定文件)
	if models.Module.X是系统文件夹(指定文件) {
		return errorx.New("无法删除系统文件夹")
	}
	被删除的文件 := models.Module.Get编辑器路径() + "/" + 指定文件
	if strings.HasPrefix(被删除的文件, "recycle") {
		return os.Remove(被删除的文件)
	} else {
		回收路径 := models.Module.Get回收路径() + "/" + 指定文件
		回收路径, err = pathx.S生成不重复的文件路径(回收路径)
		if err != nil {
			return
		}
		mkerr := os.MkdirAll(filepath.Dir(回收路径), fs.ModePerm)
		if mkerr != nil {
			return mkerr
		}
		return afero.NewOsFs().Rename(被删除的文件, 回收路径)
	}

}
func (*FileService) Rename(源路径, 新路径 string) error {
	osfs := afero.NewOsFs()
	// 重命名目录
	源配置路径 := models.Module.Get编辑器路径() + "/" + 源路径
	_, err源路径 := filex.NewFileInfo(源配置路径)
	if err源路径 != nil {
		return errorx.Wrap(err源路径, "获取文件信息", datax.M{"源路径": 源路径})
	}
	新配置路径 := models.Module.Get编辑器路径() + "/" + 新路径
	_, err新路径 := filex.NewFileInfo(新配置路径)
	if err新路径 == nil {
		return errorx.New("新路径已经存在", datax.M{"新路径": 新路径})
	}

	errRename := osfs.Rename(源配置路径, 新配置路径)
	if errRename != nil {
		return errRename
	}
	return nil
}
func (*FileService) _Rename(源路径, 新路径 string) ([][]string, error) {
	if models.Module.X是系统文件夹(源路径) {
		return nil, errorx.New("无法重命名系统文件夹", datax.M{"源路径": 源路径})
	}
	源路径 = filepath.ToSlash(源路径)
	新路径 = filepath.ToSlash(新路径)

	源配置路径 := models.Module.Get编辑器路径() + "/" + 源路径
	源路径文件信息, err源路径 := filex.NewFileInfo(源配置路径)
	if err源路径 != nil {
		return nil, errorx.Wrap(err源路径, "获取文件信息", datax.M{"源路径": 源路径})
	}
	新配置路径 := models.Module.Get编辑器路径() + "/" + 新路径
	_, err新路径 := filex.NewFileInfo(新配置路径)
	if err新路径 == nil {
		return nil, errorx.New("新路径已经存在", datax.M{"新路径": 新路径})
	}
	arr := [][]string{}
	if 源路径文件信息.IsDir() == false {
		err := os.Rename(源配置路径, 新配置路径)
		if err != nil {
			return nil, err
		}
		arr = append(arr, []string{
			strings.Replace(源配置路径, models.Module.Get编辑器路径()+"/", "", -1),
			strings.Replace(新配置路径, models.Module.Get编辑器路径()+"/", "", -1),
		})
	} else {

		mkerr := os.MkdirAll(新配置路径, fs.ModePerm)
		if mkerr != nil {
			return nil, mkerr
		}
		var 源文件集 []filex.IFileInfo
		源文件集 = filex.NewFilter().Recursive().GetFileInfosByPath(源配置路径)

		for _, val := range 源文件集 {
			if val.Path() == 源配置路径 {
				continue
			}

			fromPath := filepath.ToSlash(val.Path())
			relpath, _ := filepath.Rel(源配置路径, val.Path())
			dir := 新配置路径
			toPath := dir + "/" + relpath
			if fromPath == toPath {
				continue
			}
			errRename := os.Rename(fromPath, toPath)
			if errRename != nil {
				return nil, errorx.Wrap(errRename, "重命名")
			}

			arr = append(arr, []string{
				strings.Replace(fromPath, models.Module.Get编辑器路径()+"/", "", -1),
				strings.Replace(toPath, models.Module.Get编辑器路径()+"/", "", -1),
			})
		}

		os.Remove(源配置路径)
	}

	return arr, nil
}

func (*FileService) MoveFile(源路径, 新路径 string) ([][]string, error) {
	if models.Module.X是系统文件夹(源路径) {
		return nil, errorx.New("无法移动系统文件夹", datax.M{"源路径": 源路径})
	}

	源路径 = models.Module.Get编辑器路径() + "/" + 源路径
	源文件, err := filex.NewFileInfo(源路径)
	if err != nil {
		return nil, errorx.Wrap(err, "获取文件信息", datax.M{"源路径": 源路径})
	}
	var 源文件集 []filex.IFileInfo
	if 源文件.IsDir() {
		源文件集 = filex.NewFilter().GetFileInfosByPath(源路径)
	} else {
		源文件集 = append(源文件集, 源文件)
	}

	新路径 = models.Module.Get编辑器路径() + "/" + 新路径
	新文件, err := filex.NewFileInfo(新路径)
	if err != nil {
		return nil, errorx.Wrap(err, "获取文件信息", datax.M{"新路径": 新路径})
	}

	if 新文件.IsDir() == false {
		return nil, nil
	}

	arr := [][]string{}
	for _, val := range 源文件集 {
		fromPath := filepath.ToSlash(val.Path())
		base := filepath.Base(fromPath)
		dir := filepath.ToSlash(新文件.Path())
		toPath := dir + "/" + base
		if fromPath == toPath {
			continue
		}
		toPath, err = pathx.S生成不重复的文件路径(toPath)
		if err != nil {
			continue
		}
		err = os.Rename(fromPath, toPath)
		if err != nil {
			return nil, errorx.Wrap(err, "重命名")
		}

		arr = append(arr, []string{
			strings.Replace(fromPath, models.Module.Get编辑器路径()+"/", "", -1),
			strings.Replace(toPath, models.Module.Get编辑器路径()+"/", "", -1),
		})
	}
	return arr, nil
}

func (p *FileService) Save(内容 string) error {
	if 内容 == "" {
		return nil
	}
	filemaps := map[string]interface{}{}
	err := json.Unmarshal([]byte(内容), &filemaps)
	if err != nil {
		return errorx.Wrap(err, fmt.Sprintf("解析"))
	}
	for key, val := range filemaps {
		content, jsonerr := json.MarshalIndent(val, "", "\t")
		if jsonerr != nil {
			return errorx.Wrap(jsonerr, fmt.Sprintf("编码"))
		}
		err = p.SaveFile(key, string(content))
		if err != nil {
			return err
		}
	}
	return nil
}

func (p *FileService) SaveFile(路径 string, 内容 string) (err error) {
	路径 = models.Module.Get编辑器路径() + "/" + 路径
	//has, err := osx.Exists(路径)
	//if err != nil {
	//	return err
	//}
	//if !has {
	//	return errorx.New("文件不存在")
	//}

	路径 = filepath.ToSlash(路径)
	mkerr := os.MkdirAll(filepath.Dir(路径), fs.ModePerm)
	if mkerr != nil {
		return mkerr
	}

	err = os.WriteFile(路径, []byte(内容), fs.ModePerm)
	if err != nil {
		err = errorx.Wrap(err, "os.WriteFile", datax.M{"路径": 路径})
		return err
	}
	return nil
}

func (p *FileService) SaveConfig(config *configx.ConfigTreeItem) error {
	b, err := json.MarshalIndent(config.ToMap(), "", "\t")
	if err != nil {
		return errorx.Wrap(err, "json.MarshalIndent")
	}
	return p.SaveFile(config.W文件, string(b))
}

func (p *FileService) Publish() error {
	{ // 配置文件
		set, errs := p.GetFileConfigAllMap()
		_ = errs

		repo := configx.NewConfigRepo()
		repo.Load(set)

		b, err := json.MarshalIndent(sr.Config.ToSaveFileMap(repo), "", "\t")
		if err != nil {
			return errorx.Wrap(err, "MarshalIndent")
		}
		_ = b
		配置路径 := models.Module.H获取发布路径() + "/config.json"
		err = os.WriteFile(配置路径, b, os.ModePerm)
		if err != nil {
			return errorx.Wrap(err, "os.WriteFile", datax.M{"路径": 配置路径})
		}
		{
			需要包含的资源 := p.get需要包含的资源(repo)
			//

			metaPath := models.Module.H获取资源路径的meta()
			metaBytes, errReadFile := os.ReadFile(metaPath)
			if errReadFile != nil {
				return errorx.New("读取meta文件失败")
			}
			metaMap := map[string]interface{}{}
			errUnmarshal := json.Unmarshal(metaBytes, &metaMap)
			if errUnmarshal != nil {
				return errorx.New("解析meta文件失败")
			}
			userData := mapx.Map(metaMap, "userData")
			isBundle := mapx.Bool(userData, "isBundle")
			if isBundle {
				是否发生了变化 := func() bool {
					var 已存在字典 = map[string]bool{}
					var 计数 = 0
					bundleFilterConfig := mapx.Array(userData, "bundleFilterConfig")
					for _, ibundleFilterConfigItem := range bundleFilterConfig {
						bundleFilterConfigItem := ibundleFilterConfigItem.(map[string]interface{})
						if bundleFilterConfigItem == nil {
							continue
						}
						patchOption := maputil.Map(bundleFilterConfigItem, "patchOption")
						value := maputil.String(patchOption, "value")
						已存在字典[value] = true
						计数++
					}
					if len(需要包含的资源) != 计数 {
						return true
					}

					for _, path := range 需要包含的资源 {
						if !已存在字典[path] {
							return true
						}
					}
					return true
				}()

				if 是否发生了变化 {
					var bundleFilterConfig []interface{}
					for _, 路径 := range 需要包含的资源 {
						var item = map[string]interface{}{
							"range": "include",
							"type":  "url",
							"patchOption": map[string]interface{}{
								"patchType": "contain",
								"value":     路径,
							},
						}
						bundleFilterConfig = append(bundleFilterConfig, item)
					}
					userData["bundleFilterConfig"] = bundleFilterConfig
					//
					bContent, errMarshalIndent := json.MarshalIndent(metaMap, "", "\t")
					if errMarshalIndent != nil {
						return errorx.New("打包meta文件失败")
					}
					if string(metaBytes) != string(bContent) {
						err = os.WriteFile(metaPath, bContent, os.ModePerm)
						if err != nil {
							return errorx.Wrap(err, "os.WriteFile", datax.M{"路径": metaPath})
						}
					}
				}
			}

		}

	}

	{ // 场景配置文件
		场景路径 := models.Module.H获取文件路径("config/world/场景")
		mainFiles := filex.NewFilter().
			IncludeFile("main.ycj").
			IgnoreDir(models.Module.H获取文件路径("config/recycle")).
			GetFileInfosByPath(场景路径)
		for _, mainFile := range mainFiles {
			mainPath := filepath.ToSlash(filepath.Dir(mainFile.Path()))
			sceneFiles := filex.NewFilter().
				IncludeSuffix(".ycj", ".map").
				GetFileInfosByPath(mainPath)

			set, _ := p.GetFileConfig(sceneFiles)
			last := map[string]interface{}{}
			for _, configs := range set {
				for k, c := range configs {
					last[k] = c
				}
			}
			bcontent, err := json.MarshalIndent(last, "", "\t")
			if err != nil {
				return errorx.Wrap(err, "MarshalIndent")
			}

			reltivePath := strings.Replace(mainPath, 场景路径, "", -1) + ".scj"
			{
				targetPath := models.Module.H获取发布路径() + "/scene" + reltivePath
				dir := filepath.Dir(targetPath)
				mkerr := os.MkdirAll(dir, os.ModePerm)

				if mkerr != nil {
					return errorx.Wrap(mkerr, "os.MkdirAll", datax.M{"路径": mainPath})
				}
				err = os.WriteFile(targetPath, bcontent, os.ModePerm)
				if err != nil {
					return errorx.Wrap(err, "os.WriteFile", datax.M{"路径": mainPath})
				}

			}
		}

	}

	return nil
}

func (p *FileService) Get资源配置文件列表() []filex.IFileInfo {
	var list []filex.IFileInfo
	list = append(list, filex.NewFilter().
		IncludeSuffix(".ycj").
		GetFileInfosByPath(models.Module.Get编辑器路径()+"/config/asset")...,
	)
	list = append(list, filex.NewFilter().
		IncludeSuffix(".ycj").
		GetFileInfosByPath(models.Module.Get编辑器路径()+"/config/core")...,
	)

	return list
}

func (p *FileService) Get资源文件列表() []filex.IFileInfo {
	var list []filex.IFileInfo

	list = append(list, filex.NewFilter().
		IncludeSuffix(".meta").
		Validator(func(ifile filex.IFileInfo) bool {
			if ifile.IsDir() {
				if string(ifile.Name()[0]) == "_" {
					return false
				}
			}
			return true
		}).
		GetFileInfosByPath(models.Module.Get资源路径())...,
	)
	return list
}

func (p *FileService) get需要包含的资源(repo *configx.ConfigRepo) []string {
	需要过滤的分类 := func(link string) bool {
		if link == "模型" ||
			link == "图标" ||
			link == "纹理" ||
			link == "地块" ||
			link == "地形" ||
			link == "预设" ||
			link == "音效" ||
			link == "音乐" {
			return true
		}
		return false
	}
	需要包含的资源 := map[string]bool{}
	repo.ForRange(func(key string, configItem *configx.ConfigTreeItem) (err error) {
		configItem.WalkField(func(classDecl *schemax.ClassDecl, field *schemax.Field, ival interface{}) {
			link := field.Tags["link"]
			if !需要过滤的分类(link) {
				return
			}
			编号 := convertx.AnyToString(ival)
			if 编号 == "" {
				return
			}

			配置 := repo.GetBy编号(编号)
			if 配置 == nil {
				return
			}
			if 配置.M默认 {
				return
			}

			相对路径 := 配置.M名称

			switch 配置.L类型 {
			case "模型":
				需要包含的资源["模型/"+相对路径] = true
			case "音乐":
				需要包含的资源["音乐/"+相对路径] = true
			case "音效":
				需要包含的资源["音效/"+相对路径] = true
			case "图标":
				需要包含的资源["图标/"+相对路径] = true
			case "预设":
				需要包含的资源["预设/"+相对路径] = true
			case "地块":
				需要包含的资源["地块/"+相对路径] = true
			case "地形":
				需要包含的资源["地形/"+相对路径] = true
			}
		})
		return nil
	})

	var 需要包含的资源列表 []string
	for key, _ := range 需要包含的资源 {
		需要包含的资源列表 = append(需要包含的资源列表, key)
	}
	sort.Strings(需要包含的资源列表)
	return 需要包含的资源列表
}
